import ustruct
import modbus as mb
import utime as time
import urandom




mb.init("modbus_485")

voltage_add = 1
relay_add = 2
voltage_add = 1
volt_channel = 10



def turn_on_relay_one(relay_num):
    """
    brief: 打开1-3其中一个继电器开关
    """
    if relay_num == 1:         
        ret = mb.writeHoldingRegister(relay_add, 0, 1, 200)
        if ret[0] != 0:
            print("Error: %d" % ret[0])
    if relay_num == 2:         
        ret = mb.writeHoldingRegister(relay_add, 1, 1, 200)
        if ret[0] != 0:
            print("Error: %d" % ret[0])
    if relay_num == 3:         
        ret = mb.writeHoldingRegister(relay_add, 2, 1, 200)
        if ret[0] != 0:
            print("Error: %d" % ret[0])

def turn_off_relay_one(relay_num):
    """
    brief: 关闭1-3其中一个继电器开关
    """
    if relay_num == 1:         
        ret = mb.writeHoldingRegister(relay_add, 0, 0, 200)
        if ret[0] != 0:
            print("Error: %d" % ret[0])
    if relay_num == 2:         
        ret = mb.writeHoldingRegister(relay_add, 1, 0, 200)
        if ret[0] != 0:
            print("Error: %d" % ret[0])
    if relay_num == 3:         
        ret = mb.writeHoldingRegister(relay_add, 2, 0, 200)
        if ret[0] != 0:
            print("Error: %d" % ret[0])

def turn_on_relay_all():
    ret = mb.writeHoldingRegister(relay_add, 52, 1, 200)
    if ret[0] != 0:
        print("Error: %d" % ret[0])
    
def turn_off_relay_all():  
    ret = mb.writeHoldingRegister(relay_add, 52, 0, 200)
    if ret[0] != 0:
        print("Error: %d" % ret[0])
# 获取继电器状态
def get_relay_status():
    value = bytearray(6)
    # 发送命令 02 03 00 00 00 03 05 F8   全开 02 03 06 00 01 00 01 00 01 98 45
    ret = mb.readHoldingRegisters(relay_add, 0, 3, value, 200)
    if ret[0] != 0:
        print("Error: %d" % ret[0])
        return 6,6,6
    data= ustruct.unpack('hhh',value)
    return data[0],data[1],data[2]


# 8通道模拟信号输入
def read_volt_all_channel():
    '''
    brief: 获取所有模拟通道数据
    return: 返回列表数据
    '''
    value = bytearray(20)
    result = [0]*volt_channel
    ret = mb.readInputRegisters(voltage_add,0,10,value,200)
    # 数据解析后为10进制数据，第一位为小数点位数，如31023，实际值1.023V
    if ret[0] !=0:
        time.sleep(0.05)
        ret = mb.readInputRegisters(voltage_add,0,10,value,300)
        if ret[0] != 0:
            print("ErrorVolt: %d" % ret[0])
            return [99]*volt_channel
    data = ustruct.unpack('HHHHHHHHHH',value)
    i = 0
    while i < len(data):
        num = data[i]
        if num == 0:
            result[i] = 0
        else:
            decimal_place = num // 10000
            valid_data = num % 10000
            actual_data = valid_data * (10**(-decimal_place))
            result[i] = actual_data
        i += 1
    return result  #分别对应模拟通道1-8

def read_soil_sensor(addr=1,retries=2, delay_ms=100):
    '''
    brief: 读取水分传感器数据
    return: 返回列表数据
    '''
    time.sleep(0.2)
    readBuf = bytearray(4)
    for attempt in range(retries):
        ret = mb.readHoldingRegisters(addr, 0, 2, readBuf, 2000)
        if ret[0] == 0:
            # 读取成功
            data = ustruct.unpack('HH', readBuf)
            return data
        else:
            print("Error reading sensor at address %d: %d (Attempt %d)" % (addr, ret[0], attempt + 1))
            if attempt < retries - 1:
                time.sleep(delay_ms / 1000.0) # 重试前延时
    # 所有重试都失败
    print("Failed to read sensor at address %d after %d attempts." % (addr, retries))
    return (999,999) # 返回一个特定的错误码

def read_flow_caf():
    '''
    brief: 读取流量传感器数据
    return: 返回列表数据
    '''
    value = bytearray(2)
    ret = mb.readHoldingRegisters(4, 2, 1, value, 300)
    if ret[0] != 0:
        time.sleep(0.05)
        ret = mb.readHoldingRegisters(4, 2, 1, value, 300)
        if ret[0] != 0:
            print("ErrorFlow: %d" % ret[0])
            return [99]
    data = ustruct.unpack('h', value)
    return [data[0]*10]

def read_virtual_soil_sensor( addr=1, retries=2, delay_ms=100):
    '''
    brief: 返回虚拟的水分传感器数据（用于测试）
    return: 返回列表数据,格式与read_soil_sensor相同
    '''
    time.sleep(0.2)  # 模拟读取延时
    soil = urandom.randint(20, 80)  # 湿度20%-80%
    temperature = urandom.randint(150, 350)  # 温度15-35度的10倍表示
    return (soil, temperature)






  

    
    
    